package model

import (
	"github.com/go-xorm/builder"
	"github.com/go-xorm/xorm"
	"log"
	"time"
)

// 顾客
type Customer struct {
	Id        int64
	Name      string    `xorm:"notnull"`             // 客户姓名
	Nick      string    `xorm:"notnull default('')"` // 客户昵称
	CreatedAt time.Time `xorm:"created"`
	UpdatedAt time.Time `xorm:"updated"`
}

type customerJoinPhoneAndAddress struct {
	Id        int64
	Name      string
	Nick      string
	CreatedAt time.Time
	UpdatedAt time.Time
	AddressId int64
	Address   string
	PhoneId   int64
	Tel       string
	PostCode  string
}

type CustomerResult struct {
	Id        int64  `json:"id"`
	Name      string `json:"name"`
	Nick      string `json:"nick"`
	CreatedAt int64
	UpdatedAt int64
	Phone     []PhoneResult
	Address   []AddressResult
}

func (c *Customer) Create(tels, address []string) (int64, error) {
	res, err := GetDB().Transaction(func(s *xorm.Session) (interface{}, error) {
		// 插入数据到 customer 表
		affected, err := s.Insert(c)
		if err != nil {
			return 0, err
		}
		// 插入数据到 phone 表
		//phoneSlice := make([]Phone, len(tels))
		var phoneSlice []Phone
		for _, v := range tels {
			phoneSlice = append(phoneSlice, Phone{
				CustomerId: c.Id,
				Tel:        v,
			})
		}
		_, err = s.Insert(&phoneSlice)
		if err != nil {
			return 0, err
		}
		// 插入数据到 address 表
		//addressSlice := make([]Address, len(address))
		var addressSlice []Address
		for _, v := range address {
			addressSlice = append(addressSlice, Address{
				CustomerId: c.Id,
				Address:    v,
			})
		}
		_, err = s.Insert(&addressSlice)
		if err != nil {
			return 0, err
		}
		return affected, nil
	})
	if err != nil {
		log.Printf("创建客户失败：%v", err)
		return 0, err
	}
	return res.(int64), err
}

func (c *Customer) DeleteMulti(ids []int) error {
	// 批量删除客户
	_, err := GetDB().Transaction(func(s *xorm.Session) (interface{}, error) {
		// 删除 customer 表中数据
		_, err := s.In("id", ids).Delete(c)
		if err != nil {
			return nil, err
		}
		// 删除 phone 表中数据
		_, err = s.In("customer_id", ids).Delete(&Phone{})
		if err != nil {
			return nil, err
		}
		// 删除 address 表中数据
		_, err = s.In("customer_id", ids).Delete(&Address{})
		return nil, nil
	})
	if err != nil {
		log.Printf("删除客户失败：%v", err)
		return err
	}
	return nil
}

func (c *Customer) Update(phone, address []string) error {
	_, err := GetDB().Transaction(func(s *xorm.Session) (interface{}, error) {
		// 删除旧的 phone
		_, err := s.Where("customer_id = ?", c.Id).Delete(Phone{})
		if err != nil {
			log.Printf("[db 更新客户信息] failed: %v", err)
			return nil, err
		}
		// 删除旧的 address
		_, err = s.Where("customer_id = ?", c.Id).Delete(Address{})
		if err != nil {
			log.Printf("[db 更新客户信息] failed: %v", err)
			return nil, err
		}
		// 添加新的 phone
		var phoneSlice []Phone
		for _, v := range phone {
			phoneSlice = append(phoneSlice, Phone{
				CustomerId: c.Id,
				Tel:        v,
			})
		}
		_, err = s.Insert(&phoneSlice)
		if err != nil {
			log.Printf("[db 更新客户信息] failed: %v", err)
			return nil, err
		}
		// 添加新的 address
		var addressSlice []Address
		for _, v := range address {
			addressSlice = append(addressSlice, Address{
				CustomerId: c.Id,
				Address:    v,
			})
		}
		_, err = s.Insert(&addressSlice)
		if err != nil {
			log.Printf("[db 更新客户信息] failed: %v", err)
			return nil, err
		}
		// 更新 customer
		_, err = s.Table(&Customer{}).ID(c.Id).Update(map[string]interface{}{
			"name": c.Name,
			"nick": c.Nick,
		})
		if err != nil {
			log.Printf("[db 更新客户信息] failed: %v", err)
			return nil, err
		}
		return nil, nil
	})
	if err != nil {
		log.Printf("[db 更新客户信息] failed: %v", err)
		return err
	}
	return nil
}

func (c *Customer) All(query string, pn, ps int) ([]CustomerResult, int, error) {

	var results []customerJoinPhoneAndAddress
	x := GetDB()

	total, err := x.
		Where(builder.Like{"name", "%" + query + "%"}.Or(builder.Like{"nick", "%" + query + "%"})).
		Count(c)

	if err != nil {
		log.Printf("[db 客户列表] failed: %v", err)
		return nil, 0, err
	}

	err = x.SQL(`
SELECT
	a.id id,
	a.name name,
	a.nick nick,
	a.created_at,
	a.updated_at,
	b.id phone_id,
	b.tel tel,
	c.id address_id,
	c.address address,
	c.post_code post_code 
FROM
	( SELECT * FROM customer WHERE name LIKE ? OR nick LIKE ? ORDER BY id DESC LIMIT ?, ? ) a
	LEFT JOIN phone b ON b.customer_id = a.id
	LEFT JOIN address c ON c.customer_id = a.id
	ORDER BY a.id DESC, b.id, c.id
`, "%"+query+"%", "%"+query+"%", (pn-1)*ps, ps).Find(&results)

	if err != nil {
		log.Printf("[db 客户列表] failed: %v", err)
		return nil, 0, err
	}

	r := aggregationCustomer(results)

	return r, int(total), nil

}

//func (c *Customer) All() ([]CustomerResult, int, error) {
//
//}

//func (c *Customer) Delete() error {
//	if c.Id == 0 {
//		err := errors.New("删除客户时，id 不能为空")
//		log.Printf("删除客户失败：%v", err)
//		return err
//	}
//	db := GetDB()
//	err := db.Delete(c).Error
//	if err != nil {
//		log.Printf("删除客户失败：%v", err)
//		return err
//	}
//	return nil
//}
//
//func (c *Customer) Update(phone, address []string) error {
//	if c.Id == 0 {
//		err := errors.New("更新客户时，id 不能为空")
//		log.Printf("更新客户失败：%v", err)
//		return err
//	}
//	// 删除原来的 phone 和 address
//
//	// 新建 phone 和 address
//
//	return nil
//}

func aggregationCustomer(customers []customerJoinPhoneAndAddress) []CustomerResult {
	var results []CustomerResult
	lastCustomerId := int64(-1)
	//lastPhoneId := int64(-1)

	for _, c := range customers {

		if c.Id != lastCustomerId {
			// 新的 customer
			results = append(results, CustomerResult{
				Id:        c.Id,
				Name:      c.Name,
				Nick:      c.Nick,
				CreatedAt: c.CreatedAt.Unix(),
				UpdatedAt: c.UpdatedAt.Unix(),
			})
			lastCustomerId = c.Id
		}

		phone := &results[len(results)-1].Phone
		*phone = append(*phone, PhoneResult{
			Id:  c.PhoneId,
			Tel: c.Tel,
		})

		address := &results[len(results)-1].Address
		*address = append(*address, AddressResult{
			Id:      c.AddressId,
			Address: c.Address,
		})
	}

	// 将 phone 和 address 去一下重
	for i := range results {
		r := &results[i]
		r.Phone = uniquePhone(r.Phone)
		r.Address = uniqueAddress(r.Address)
		log.Println("result: %+v", results[i])
	}

	log.Printf("results: %+v", results)
	return results
}

func uniquePhone(phone []PhoneResult) []PhoneResult {
	var results []PhoneResult
	tmp := map[int64]PhoneResult{}
	for _, p := range phone {
		tmp[p.Id] = p
	}
	for _, p := range tmp {
		results = append(results, p)
	}
	return results
}

func uniqueAddress(address []AddressResult) []AddressResult {
	var results []AddressResult
	tmp := map[int64]AddressResult{}
	for _, a := range address {
		tmp[a.Id] = a
	}
	for _, a := range tmp {
		results = append(results, a)
	}
	return results
}
